# coding: utf-8
import base64
from random import randint
from typing import Union

from PySide6.QtCore import Signal, QUrl, Qt, QSize, QByteArray, QIODevice, QBuffer
from PySide6.QtGui import QImage, QPixmap, QImageReader, QMovie, QIcon, QPainter, QColor, QPainterPath, QEnterEvent
from PySide6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
from PySide6.QtWidgets import QLabel, QWidget, QHBoxLayout, QFileDialog
from qfluentwidgets import ImageLabel, IconWidget, FluentIconBase, FluentIcon, TransparentToolButton, ToolTipFilter
from qfluentwidgets.common.overload import singledispatchmethod

from .button import ElPrimaryButton
from .picture_browser import PictureDialog
from ...common import ElIcon


class LabelButton(TransparentToolButton):
    def _postInit(self):
        self.setFixedSize(32, 32)
        self.installEventFilter(ToolTipFilter(self))


class ElImageLabel(ImageLabel):
    finished = Signal()
    error = Signal(str)

    @singledispatchmethod
    def __init__(self, parent: QWidget = None):
        QLabel.__init__(self, parent)
        self.image = QImage()
        self.manager = QNetworkAccessManager(self)
        self.reply = None
        self._url = QUrl()
        self._randomColor = QColor(randint(0, 255), randint(0, 255), randint(0, 255), 50)
        self._enableRandomColor = True

        self.iconWidget = IconWidget(self)
        self.reloadButton = ElPrimaryButton(ElIcon.Refresh, self.tr('重新加载'), self)
        self.iconWidget.setFixedSize(80, 80)
        self.reloadButton.setFixedSize(150, 32)

        self.reloadButton.clicked.connect(self.reload)
        self.iconWidget.setVisible(False)
        self.reloadButton.setVisible(False)

        self.setBorderRadius(0, 0, 0, 0)

        self._postInit()

    @__init__.register
    def _(self, image: str, parent=None):
        self.__init__(parent)
        if image.startswith('http'):
            self.setUrl(image)
        else:
            self.setImage(image)

    @__init__.register
    def _(self, image: QImage, parent=None):
        self.__init__(parent)
        self.setImage(image)

    @__init__.register
    def _(self, image: QPixmap, parent=None):
        self.__init__(parent)
        self.setImage(image)

    @__init__.register
    def _(self, url: QUrl, parent=None):
        self.__init__(parent)
        self.setUrl(url)

    def _onFinished(self):
        if self.reply.error() == QNetworkReply.NetworkError.NoError:
            image = QImage()
            image.loadFromData(self.reply.readAll())
            self.setImage(image)
        else:
            self.setIcon(FluentIcon.PHOTO)
            self.reloadButton.setVisible(True)
            self.error.emit(self.reply.errorString())
        self.reply.deleteLater()
        self.reply = None
        self.finished.emit()

    def setIcon(self, icon: Union[str, QIcon, FluentIconBase]):
        self.iconWidget.setIcon(icon)
        self.iconWidget.setVisible(True)

    def setIconSize(self, size: QSize):
        self.iconWidget.setFixedSize(size)

    def url(self) -> QUrl:
        return self._url

    def setUrl(self, url: Union[str, QUrl], headers=None):
        self._url = QUrl(url)
        self.reloadButton.setVisible(False)
        self.iconWidget.setVisible(False)

        request = QNetworkRequest(self._url)
        if headers:
            for key, value in headers.items():
                request.setRawHeader(key.encode(), value.encode())
        self.reply = self.manager.get(request)
        self.reply.finished.connect(self._onFinished)

    def setImage(self, image: Union[str, QPixmap, QImage] = None):
        """ set the image of label """
        self.image = image or QImage()

        if isinstance(image, str):
            reader = QImageReader(image)
            if reader.supportsAnimation():
                self.setMovie(QMovie(image))
            else:
                self.image = reader.read()
        elif isinstance(image, QPixmap):
            self.image = image.toImage()

        # self.setFixedSize(self.image.size())
        self.update()

    def mouseReleaseEvent(self, e):
        QLabel.mouseReleaseEvent(self, e)
        if e.button() == Qt.MouseButton.LeftButton:
            self.clicked.emit()

    def reload(self):
        self.setUrl(self.url())

    def _createPainterPath(self) -> QPainterPath:
        path = QPainterPath()
        w, h = self.width(), self.height()

        # top line
        path.moveTo(self.topLeftRadius, 0)
        path.lineTo(w - self.topRightRadius, 0)

        # top right arc
        d = self.topRightRadius * 2
        path.arcTo(w - d, 0, d, d, 90, -90)

        # right line
        path.lineTo(w, h - self.bottomRightRadius)

        # bottom right arc
        d = self.bottomRightRadius * 2
        path.arcTo(w - d, h - d, d, d, 0, -90)

        # bottom line
        path.lineTo(self.bottomLeftRadius, h)

        # bottom left arc
        d = self.bottomLeftRadius * 2
        path.arcTo(0, h - d, d, d, -90, -90)

        # left line
        path.lineTo(0, self.topLeftRadius)

        # top left arc
        d = self.topLeftRadius * 2
        path.arcTo(0, 0, d, d, -180, -90)
        return path

    def _createPainterImage(self) -> QImage:
        image = self.image.scaled(
            self.size() * self.devicePixelRatioF(), Qt.AspectRatioMode.IgnoreAspectRatio,
            Qt.TransformationMode.SmoothTransformation)
        return image

    def paintEvent(self, e):
        painter = QPainter(self)
        painter.setRenderHints(QPainter.RenderHint.Antialiasing)
        painter.setPen(Qt.PenStyle.NoPen)
        painter.setClipPath(self._createPainterPath())
        if self.isNull():
            if self.enableRandomColor():
                painter.fillRect(self.rect(), self._randomColor)
        else:

            painter.drawImage(self.rect(), self._createPainterImage())
        painter.end()

    def resizeEvent(self, e):
        w, h = self.width(), self.height()
        self.iconWidget.move((w - self.iconWidget.width()) // 2,
                             (h - self.iconWidget.height() - self.reloadButton.height() - 10) // 2)
        self.reloadButton.move((w - self.reloadButton.width()) // 2, (
                h - self.iconWidget.height() - self.reloadButton.height() - 10) // 2 + self.iconWidget.height() + 10)
        super().resizeEvent(e)

    def setEnableRandomColor(self, enable: bool):
        self._enableRandomColor = enable
        self.update()

    def enableRandomColor(self) -> bool:
        return self._enableRandomColor

    def bytes(self, format: str = 'PNG') -> bytes:
        """
        将图片转换为字节数组
        :param format: 图片格式
        :return:
        """
        image = self.image
        if image.isNull():
            return b''
        byte_array = QByteArray()
        buffer = QBuffer(byte_array)
        buffer.open(QIODevice.OpenModeFlag.WriteOnly)
        image.save(buffer, format.upper())
        return byte_array.data()

    def base64(self, format: str = 'PNG', prefix: str = 'data:image/{};base64,') -> str:
        """
        :param format: 图片格式
        :param prefix: 前缀
        :return: base64字符串
        """
        if self.image.isNull():
            return ''
        suffix = format.upper()
        if suffix == 'JPG':
            suffix = 'JPEG'
        prefix = prefix.format(suffix)
        base64_str = prefix + base64.b64encode(self.bytes(suffix)).decode()
        return base64_str

    def save(self, file_path: str, format: str = 'PNG'):
        """
        保存图片到文件
        :param file_path: 文件路径
        :param format: 图片格式
        :return:
        """
        if self.image.isNull():
            return
        self.image.save(file_path, format.upper())


class CentreImageLabel(ElImageLabel):
    """ 居中图像标签 """

    def _createPainterPath(self) -> QPainterPath:
        path = QPainterPath()
        w, h = self.width(), self.height()

        # top line
        path.moveTo(self.topLeftRadius, 0)
        path.lineTo(w - self.topRightRadius, 0)

        # top right arc
        d = self.topRightRadius * 2
        path.arcTo(w - d, 0, d, d, 90, -90)

        # right line
        path.lineTo(w, h - self.bottomRightRadius)

        # bottom right arc
        d = self.bottomRightRadius * 2
        path.arcTo(w - d, h - d, d, d, 0, -90)

        # bottom line
        path.lineTo(self.bottomLeftRadius, h)

        # bottom left arc
        d = self.bottomLeftRadius * 2
        path.arcTo(0, h - d, d, d, -90, -90)

        # left line
        path.lineTo(0, self.topLeftRadius)

        # top left arc
        d = self.topLeftRadius * 2
        path.arcTo(0, 0, d, d, -180, -90)
        return path

    def _createPainterImage(self) -> QImage:
        image = self.image.scaled(
            self.size() * self.devicePixelRatioF(),
            Qt.AspectRatioMode.KeepAspectRatioByExpanding,
            Qt.TransformationMode.SmoothTransformation
        )  # type: QImage

        iw, ih = image.width(), image.height()
        w = self.width() * self.devicePixelRatioF()
        h = self.height() * self.devicePixelRatioF()
        x, y = (iw - w) / 2, (ih - h) / 2
        image = image.copy(int(x), int(y), int(w), int(h))
        return image


class UploadImageLabel(CentreImageLabel):
    """ 上传图像标签 """

    def _postInit(self):
        self.file_path = None

        self.horizontalLayout = QHBoxLayout(self)
        self.uploadButton = LabelButton(ElIcon.Upload, self)
        self.editButton = LabelButton(FluentIcon.EDIT, self)
        self.viewButton = LabelButton(FluentIcon.VIEW, self)
        self.deleteButton = LabelButton(FluentIcon.DELETE, self)

        self.uploadButton.setToolTip(self.tr('上传图片'))
        self.editButton.setToolTip(self.tr('编辑图片'))
        self.viewButton.setToolTip(self.tr('查看图片'))
        self.deleteButton.setToolTip(self.tr('删除图片'))

        self.horizontalLayout.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.horizontalLayout.addWidget(self.uploadButton)
        self.horizontalLayout.addWidget(self.editButton)
        self.horizontalLayout.addWidget(self.viewButton)
        self.horizontalLayout.addWidget(self.deleteButton)

        self.uploadButton.clicked.connect(self.upload)
        self.editButton.clicked.connect(self.upload)
        self.viewButton.clicked.connect(self.view)
        self.deleteButton.clicked.connect(self.delete)

        self._initButtonVisible()

    def upload(self):
        self.file_path, _ = QFileDialog.getOpenFileName(self, self.tr('上传图片'), '',
                                                        self.tr('图片文件 (*.jpg *.png, *.gif, *.jpeg, *.svg, *.ico)'))
        if self.file_path:
            self.setImage(self.file_path)
            self._initButtonVisible()

    def delete(self):
        self.setImage(QImage())
        self._initButtonVisible()

    def view(self):
        self.picture_browser = PictureDialog(self.window())
        self.picture_browser.setPixmap(self.pixmap())
        self.picture_browser.exec()

    def _onFinished(self):
        super()._onFinished()
        self._initButtonVisible()

    def _initButtonVisible(self):
        if self.isNull():
            self.uploadButton.setVisible(True)
            self.editButton.setVisible(False)
            self.viewButton.setVisible(False)
            self.deleteButton.setVisible(False)
        else:
            self.uploadButton.setVisible(False)
            self.editButton.setVisible(True)
            self.viewButton.setVisible(True)
            self.deleteButton.setVisible(True)
        if self.iconWidget.isVisible():
            self.uploadButton.setVisible(False)

    def enterEvent(self, event: QEnterEvent):
        self._initButtonVisible()
        super().enterEvent(event)

    def leaveEvent(self, event: QEnterEvent):
        self.uploadButton.setVisible(False)
        self.editButton.setVisible(False)
        self.viewButton.setVisible(False)
        self.deleteButton.setVisible(False)
        super().leaveEvent(event)

    def setImage(self, image: Union[str, QPixmap, QImage] = None):
        super().setImage(image)
        self._initButtonVisible()
